using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using igp.net.DataModel;

namespace igp.net.DataModel
{
    /// <summary>
    /// Represents a label.
    /// </summary>
    public class IgpLabel : IgpItem
    {
        private bool Edited;

        /// <summary>
        /// Default constructor.
        /// </summary>
        public IgpLabel()
        {
            FixedX = true;
            FixedY = true;
            DrawTextOnly = false;
            X = 10;
            Y = 10;
            TypeID = IgpItemType.Label;
            ItemName = "Label ";
            FillColor = Color.White;
            FrameColor = Color.Black;
            TextColor = Color.Black;
            Edited = false;
        }

        /// <summary>
        /// Gets/Sets the background color.
        /// </summary>
        public Color FillColor { get; set; }

        /// <summary>
        /// Gets/Sets the border color.
        /// </summary>
        public Color FrameColor { set; get; }

        /// <summary>
        /// Gets/Sets the text color.
        /// </summary>
        public Color TextColor { set; get; }

        /// <summary>
        /// X coordinate
        /// </summary>
        public double X { get; set; }

        /// <summary>
        /// Y coordinate
        /// </summary>
        public double Y { get; set; }

        private double Xo { get; set; }

        private double Yo { get; set; }

        /// <summary>
        /// If true the label will have it's x coordinate in pixels. I
        /// t will stick to the screen rather than move along with the view.
        /// </summary>
        public bool FixedX { get; set; }

        /// <summary>
        /// If true the label will have it's y coordinate in pixels. I
        /// t will stick to the screen rather than move along with the view.
        /// </summary>
        public bool FixedY { get; set; }

        /// <summary>
        /// If true draws the text only.
        /// </summary>
        public bool DrawTextOnly { get; set; }

        private Rectangle GetRect(Graphics graph)
        {
            var height = (int) (Math.Ceiling(igpSettings.Singleton.ChartFont.Size) + 6);
            int width = 10 + (int) graph.MeasureString(ItemName, igpSettings.Singleton.ChartFont).Width;

            int dx = FixedX ? (int) X : IgpProject.Singleton.View.GetScreenCoordinateX(X);
            int dy = FixedY ? (int) Y : IgpProject.Singleton.View.GetScreenCoordinateY(Y);

            return new Rectangle(dx, dy, width, height);
        }

        /// <summary>
        /// Draws the label on the screen.
        /// </summary>
        /// <param name="graph">Graphics object used for drawing.</param>
        public override void Draw(Graphics graph)
        {
            Rectangle rect = GetRect(graph);

            if (!DrawTextOnly)
            {
                graph.FillRectangle(new SolidBrush(FillColor), rect);
                graph.DrawRectangle(new Pen(FrameColor), rect);
            }

            if (Edited)
            {
                DrawCoordinates(graph);
            }

            graph.DrawString(ItemName, igpSettings.Singleton.ChartFont, new SolidBrush(TextColor), rect.X + 3,
                             rect.Y + 2);
        }

        /// <summary>
        /// Saves data to a TextWriter.
        /// </summary>
        /// <param name="sw">data output</param>
        public override void SaveData(TextWriter sw)
        {
            sw.WriteLine("<label>");
            sw.WriteLine("ItemName = {0}", ItemName);
            sw.WriteLine("X = {0}", X);
            sw.WriteLine("Y = {0}", Y);
            sw.WriteLine("FixedX = {0}", FixedX);
            sw.WriteLine("FixedY = {0}", FixedY);
            sw.WriteLine("DrawTextOnly = {0}", DrawTextOnly);
            sw.WriteLine("FillColor = {0}", FillColor.ToArgb());
            sw.WriteLine("FrameColor = {0}", FrameColor.ToArgb());
            sw.WriteLine("TextColor = {0}", TextColor.ToArgb());
            sw.WriteLine("IsVisible = {0}", IsVisible);
            //sw.WriteLine("OnLegend = {0}", this.VisibleOnLegend);
            sw.WriteLine("</label>");
        }

        /// <summary>
        /// Loads data from a TextReader.
        /// </summary>
        /// <param name="sr">data input</param>
        public override void ReadData(TextReader sr)
        {
            String Line;
            while ((Line = sr.ReadLine()) != "</label>")
            {
                char[] sep = {'=', '|'};
                String[] cmd = Line.Split(sep, 3);

                if (cmd[0].StartsWith("ItemName"))
                {
                    ItemName = cmd[1].Substring(1, cmd[1].Length - 1);
                }

                if (cmd[0].StartsWith("X"))
                {
                    X = double.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("Y"))
                {
                    Y = double.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("FixedX"))
                {
                    FixedX = bool.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("FixedY"))
                {
                    FixedY = bool.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("DrawTextOnly"))
                {
                    DrawTextOnly = bool.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("FillColor"))
                {
                    FillColor = Color.FromArgb(int.Parse(cmd[1]));
                }

                if (cmd[0].StartsWith("FrameColor"))
                {
                    FrameColor = Color.FromArgb(int.Parse(cmd[1]));
                }

                if (cmd[0].StartsWith("TextColor"))
                {
                    TextColor = Color.FromArgb(int.Parse(cmd[1]));
                }
                if (cmd[0].StartsWith("Visible"))
                {
                    IsVisible = bool.Parse(cmd[1]);
                }
            }
        }

        private void DrawCoordinates(Graphics graph)
        {
            IgpView view = IgpProject.Singleton.View;
            double tempX = FixedX ? X : view.GetScreenCoordinateX(X);
            double tempY = FixedY ? Y : view.GetScreenCoordinateY(Y);

            var px = (int) Math.Min(Math.Max(tempX + 5, 25), view.Width - 60);
            var py = (int) Math.Min(Math.Max(tempY - 15, 5), view.Height - 25);

            graph.DrawString(
                "X:" + tempX,
                igpSettings.Singleton.ChartFont,
                new SolidBrush(view.Axes.LineColor),
                px,
                py);

            graph.DrawString(
                "Y:" + tempY,
                igpSettings.Singleton.ChartFont,
                new SolidBrush(view.Axes.LineColor),
                px + 30,
                py);
        }

        /// <summary>
        /// This method is required for item's reaction to mouse buttons being pressed. 
        /// You must invoke this base method in your derived class in order 
        /// to update some useful properties.
        /// </summary>
        /// <param name="graph">Graphics object that can be used to paint something on the screen</param>
        /// <param name="e">Mouse Event Details</param>
        public override void InteractDown(Graphics graph, MouseEventArgs e)
        {
            base.InteractDown(graph, e);
            
            if (InteractionInUse) return;
            if (!GetRect(graph).Contains(e.X, e.Y) || e.Button != MouseButtons.Left) return;
            
            Edited = true;
            InteractionInUse = true;
            Xo = X;
            Yo = Y;
        }

        /// <summary>
        /// This method is required for item's reaction to mouse movement. 
        /// You must invoke this base method in your derived class in order 
        /// to update some useful properties.
        /// </summary>
        /// <param name="graph">Graphics object that can be used to paint something on the screen</param>
        /// <param name="e">Mouse Event Details</param>
        public override void InteractMove(Graphics graph, MouseEventArgs e)
        {
            base.InteractMove(graph, e);
            
            if (!IsVisible) return;
            
            if (GetRect(graph).Contains(e.X, e.Y) && !Edited && !InteractionInUse)
            {
                graph.DrawRectangle(new Pen(Color.Red), GetRect(graph));
                DrawCoordinates(graph);
            }

            if (!Edited) return;

            //Update View Ranges
            IgpView view = IgpProject.Singleton.View;
            double DoubleVectorX = !view.LogScaleX ? VectorX/view.VDistanceX : VectorX/view.VLogDistanceX;
            double DoubleVectorY = !view.LogScaleY ? VectorY/view.VDistanceY : VectorY/view.VLogDistanceY;

            if (FixedX)
            {
                X = Xo - (int) (VectorX/view.GetRatioX());
            }
            else
            {
                X = !view.LogScaleX ? Xo - DoubleVectorX : Math.Pow(10, (Math.Log10(Xo) - DoubleVectorX/10));
            }
            if (FixedY)
            {
                Y = Yo - (int) (VectorY/view.GetRatioY());
            }
            else
            {
                Y = !view.LogScaleY ? Yo + DoubleVectorY : Math.Pow(10, (Math.Log10(Yo) + DoubleVectorY/10));
            }
        }

        /// <summary>
        /// This method is required for item's reaction to mouse buttons being released. 
        /// </summary>
        /// <param name="graph">Graphics object that can be used to paint something on the screen</param>
        /// <param name="e">Mouse Event Details</param>
        public override void InteractUp(Graphics graph, MouseEventArgs e)
        {
            base.InteractUp(graph, e);
            
            if (Edited) FormMain.Singleton.EditorWindow.ReadLabelProperities();
            
            Edited = false;
            InteractionInUse = false;
        }
    }
}